home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / djgpp / demos / ico / ico.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-12  |  26.8 KB  |  1,081 lines

  1. /* $XConsortium: ico.c,v 1.35 91/07/19 23:08:43 rws Exp $ */
  2. /***********************************************************
  3. Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
  4. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  5.  
  6.                         All Rights Reserved
  7.  
  8. Permission to use, copy, modify, and distribute this software and its
  9. documentation for any purpose and without fee is hereby granted,
  10. provided that the above copyright notice appear in all copies and that
  11. both that copyright notice and this permission notice appear in
  12. supporting documentation, and that the names of Digital or MIT not be
  13. used in advertising or publicity pertaining to distribution of the
  14. software without specific, written prior permission.
  15.  
  16. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  17. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  18. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  19. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  20. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  21. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  22. SOFTWARE.
  23.  
  24. ******************************************************************/
  25. /******************************************************************************
  26.  * Description
  27.  *    Display a wire-frame rotating icosahedron, with hidden lines removed
  28.  *
  29.  * Arguments:
  30.  *    -r        display on root window instead of creating a new one
  31.  *    =wxh+x+y    X geometry for new window (default 600x600 centered)
  32.  *    host:display    X display on which to run
  33.  * (plus a host of others, try -help)
  34.  *****************************************************************************/
  35. /* Additions by jimmc@sci:
  36.  *  faces and colors
  37.  *  double buffering on the display
  38.  *  additional polyhedra
  39.  *  sleep switch
  40.  */
  41.  
  42.  
  43. #include <X11/Xlib.h>
  44. #include <X11/Xatom.h>
  45. #include <X11/Xutil.h>
  46. #include <X11/Xfuncs.h>
  47. #include <stdio.h>
  48. #ifdef MULTIBUFFER
  49. #include <X11/extensions/multibuf.h>
  50. #endif /* MULTIBUFFER */
  51.  
  52. #ifdef MSDOS
  53. #include <stdarg.h>
  54. #endif
  55.  
  56. typedef double Transform3D[4][4];
  57.  
  58. #define MIN_ICO_WIDTH 5
  59. #define MIN_ICO_HEIGHT 5
  60. #define DEFAULT_ICO_WIDTH 150
  61. #define DEFAULT_ICO_HEIGHT 150
  62. #define DEFAULT_DELTAX 13
  63. #define DEFAULT_DELTAY 9
  64.  
  65. #include "polyinfo.h"    /* define format of one polyhedron */
  66.  
  67. /* Now include all the files which define the actual polyhedra */
  68. Polyinfo polys[] = {
  69. #include "allobjs.h"
  70. };
  71. int polysize = sizeof(polys)/sizeof(polys[0]);
  72.  
  73. typedef struct {
  74.     int prevX, prevY;
  75.     unsigned long *plane_masks;    /* points into dbpair.plane_masks */
  76.     unsigned long enplanemask;    /* what we enable for drawing */
  77.     XColor *colors;        /* size = 2 ** totalplanes */
  78.     unsigned long *pixels;    /* size = 2 ** planesperbuf */
  79. } DBufInfo;
  80.  
  81. typedef struct {
  82.     int planesperbuf;
  83.     int pixelsperbuf;    /* = 1<<planesperbuf */
  84.     int totalplanes;    /* = 2*planesperbuf */
  85.     int totalpixels;    /* = 1<<totalplanes */
  86.     unsigned long *plane_masks;    /* size = totalplanes */
  87.     unsigned long pixels[1];
  88.     int dbufnum;
  89.     DBufInfo bufs[2];
  90.     DBufInfo *drawbuf, *dpybuf;
  91. } DBufPair;
  92.  
  93. DBufPair dbpair;
  94.  
  95. XColor bgcolor,fgcolor;
  96.  
  97. #ifndef MSDOS
  98. extern long time();
  99.  
  100. extern long rand();
  101. #endif
  102.  
  103. #ifdef MSDOS
  104. void icoFatal(char *fmt,...);
  105. #endif
  106.  
  107. char *ProgramName;
  108. Display *dpy;
  109. Window win, draw_window;
  110. int winX, winY, winW, winH;
  111. int icoW = 0, icoH = 0;
  112. int icoDeltaX = DEFAULT_DELTAX, icoDeltaY = DEFAULT_DELTAY;
  113. Colormap cmap;
  114. GC gc;
  115. int multibuf = 0;
  116. #ifdef MULTIBUFFER
  117. int mbevbase, mberrbase;
  118. Multibuffer multibuffers[2];
  119. Window icowin;
  120. #endif /* MULTIBUFFER */
  121.  
  122. char *Primaries[] = {"red", "green", "blue", "yellow", "cyan", "magenta"};
  123. #define NumberPrimaries 6
  124.  
  125. int nplanesets;
  126. int dsync = 0;
  127. int softdbl = 0, dblbuf = 0;
  128. int sleepcount = 0;
  129. int msleepcount = 0;
  130. int numcolors = 0;
  131. char **colornames;    /* points into argv */
  132. int dofaces = 0;
  133. int doedges = 1;
  134.  
  135. Polyinfo *findpoly();
  136.  
  137. static char *help_message[] = {
  138. "where options include:",
  139. "    -display host:dpy            X server to use",
  140. "    -geometry geom               geometry of window to use",
  141. "    -size WxH                    size of object to rotate",
  142. "    -delta +X+Y                  amount by which to move object",
  143. "    -r                           draw in the root window",
  144. "    -d number                    dashed line pattern for wire frames",
  145. "    -bg color                    background color",
  146. "    -colors color ...            codes to use on sides",
  147. "    -p#                          use # (1 through 8) primary colors",
  148. "    -dbl                         use double buffering (extension if present)",
  149. "    -softdbl                     use software double buffering",
  150. "    -noedges                     don't draw wire frame edges",
  151. "    -faces                       draw faces",
  152. "    -copy                        copy multibuffer frames instead of clearing",
  153. "    -lw number                   line width to use",
  154. "    -i                           invert",
  155. "    -sleep number                seconds to sleep in between draws",
  156. "    -obj objname                 type of polyhedral object to draw",
  157. "    -objhelp                     list polyhedral objects available",
  158. NULL};
  159.  
  160. /******************************************************************************
  161.  * Description
  162.  *    Main routine.  Process command-line arguments, then bounce a bounding
  163.  *    box inside the window.  Call DrawIco() to redraw the icosahedron.
  164.  *****************************************************************************/
  165.  
  166. main(argc, argv)
  167. int argc;
  168. char **argv;
  169.     {
  170.     char *display = NULL;
  171.     char *geom = NULL;
  172.     int useRoot = 0;
  173.     int fg, bg;
  174.     int invert = 0;
  175.     int dash = 0;
  176.     XSetWindowAttributes xswa;
  177.     XWindowAttributes xwa;
  178.     Polyinfo *poly;        /* the poly to draw */
  179.     int icoX, icoY;
  180.     XEvent xev;
  181.     Bool blocking = False;
  182.     unsigned long vmask;
  183.     XGCValues xgcv;
  184.     int linewidth = 0;
  185.     char *background_colorname = NULL;
  186.     char *ico_geom = NULL;
  187.     char *delta_geom = NULL;
  188.     int icodeltax2, icodeltay2;
  189.     extern int _Xdebug;
  190.     int initcolors = 0;
  191. #ifdef MULTIBUFFER
  192.     int update_action = MultibufferUpdateActionBackground;
  193. #endif
  194.  
  195.     ProgramName = argv[0];
  196.  
  197.     /* Process arguments: */
  198.  
  199.     poly = findpoly("icosahedron");    /* default */
  200.  
  201.     while (*++argv) {
  202.         if (!strcmp (*argv, "-display")) {
  203.             display = *++argv;
  204.         } else if (!strncmp (*argv, "-g", 2)) {
  205.             geom = *++argv;
  206.         } else if (**argv == '=')         /* obsolete */
  207.             geom = *argv;
  208.         else if (!strcmp(*argv, "-r"))
  209.             useRoot = 1;
  210.         else if (!strcmp (*argv, "-d"))
  211.             dash = atoi(*++argv);
  212.         else if (!strcmp(*argv, "-colors")) {
  213.             colornames = ++argv;
  214.             for ( ; *argv && *argv[0]!='-'; argv++) ;
  215.             numcolors = argv - colornames;
  216.             --argv;
  217.         }
  218.         else if (!strcmp (*argv, "-copy")) {
  219. #ifdef MULTIBUFFER
  220.             update_action = MultibufferUpdateActionCopied;
  221. #endif
  222.         } else if (!strcmp (*argv, "-lw"))
  223.             linewidth = atoi(*++argv);
  224.         else if (!strcmp (*argv, "-dbl"))
  225. #ifdef MULTIBUFFER
  226.             multibuf = 1;
  227. #else
  228.             dblbuf = 1;
  229. #endif
  230.         else if (!strcmp(*argv, "-softdbl")) {
  231.             dblbuf = 1;
  232.             multibuf = 0;
  233.         }
  234.         else if (!strncmp(*argv, "-p", 2)) {
  235.             numcolors = atoi(argv[0]+2);
  236.             if (numcolors < 1 || numcolors > NumberPrimaries)
  237.               numcolors = NumberPrimaries;
  238.             colornames = Primaries;
  239.             dofaces = 1;
  240.         }
  241.         else if (!strcmp(*argv, "-bg"))
  242.             background_colorname = *++argv;
  243.         else if (!strcmp(*argv, "-noedges"))
  244.             doedges = 0;
  245.         else if (!strcmp(*argv, "-faces"))
  246.             dofaces = 1;
  247.         else if (!strcmp(*argv, "-i"))
  248.             invert = 1;
  249.         else if (!strcmp(*argv, "-size"))
  250.             ico_geom = *++argv;
  251.         else if (!strcmp(*argv, "-delta"))
  252.             delta_geom = *++argv;
  253.         else if (!strcmp (*argv, "-sleep")) {
  254.             float f = 0.0;
  255.             sscanf (*++argv, "%f", &f);
  256.             msleepcount = (int) (f * 1000.0);
  257.             sleepcount = msleepcount / 1000;
  258.         } else if (!strcmp (*argv, "-obj"))
  259.             poly = findpoly(*++argv);
  260.         else if (!strcmp(*argv, "-dsync"))
  261.             dsync = 1;
  262.         else if (!strncmp(*argv, "-sync",  5))
  263.             _Xdebug = 1;
  264.         else if (!strcmp(*argv, "-objhelp")) {
  265.             giveObjHelp();
  266.             exit(1);
  267.         }
  268.         else {    /* unknown arg */
  269.             char **cpp;
  270.  
  271.           usage:
  272.             fprintf (stderr, "usage:  %s [-options]\n\n", ProgramName);
  273.             for (cpp = help_message; *cpp; cpp++) {
  274.             fprintf (stderr, "%s\n", *cpp);
  275.             }
  276.             fprintf (stderr, "\n");
  277.             exit (1);
  278.         }
  279.     }
  280.  
  281.     if (!dofaces && !doedges) icoFatal("nothing to draw");
  282.  
  283.     if (!(dpy= XOpenDisplay(display)))
  284.             {
  285.         perror("Cannot open display\n");
  286.         exit(-1);
  287.             }
  288.  
  289. #ifdef MULTIBUFFER
  290.     if (multibuf && !XmbufQueryExtension (dpy, &mbevbase, &mberrbase)) {
  291.         multibuf = 0;
  292.         dblbuf = 1;
  293.     }
  294. #endif
  295.  
  296.     cmap = XDefaultColormap(dpy,DefaultScreen(dpy));
  297.     if (!cmap) {
  298.         icoFatal("no default colormap!");
  299.     }
  300.  
  301.     fg = WhitePixel(dpy, DefaultScreen(dpy));
  302.     bg = BlackPixel(dpy, DefaultScreen(dpy));
  303.     if (background_colorname) {
  304.         XColor cdef, igndef;
  305.  
  306.         if (XAllocNamedColor (dpy, cmap, background_colorname,
  307.                   &cdef, &igndef))
  308.           bg = cdef.pixel;
  309.         else 
  310.           icoFatal ("no such color \"%s\"", background_colorname);
  311.     }
  312.     if (numcolors && (!dofaces || numcolors == 1)) {
  313.         XColor cdef, igndef;
  314.  
  315.         if (XAllocNamedColor (dpy, cmap, colornames[0], &cdef, &igndef))
  316.           fg = cdef.pixel;
  317.         else 
  318.           icoFatal ("no such color \"%s\"", colornames[0]);
  319.     }
  320.  
  321.     if (invert) {
  322.         unsigned long tmp = fg;
  323.         fg = bg;
  324.         bg = tmp;
  325.     }
  326.  
  327.  
  328.     /* Set up window parameters, create and map window if necessary: */
  329.  
  330.     if (useRoot)
  331.         {
  332.         draw_window = DefaultRootWindow(dpy);
  333.         winX = 0;
  334.         winY = 0;
  335.         winW = DisplayWidth(dpy, DefaultScreen(dpy));
  336.         winH = DisplayHeight(dpy, DefaultScreen(dpy));
  337.         }
  338.     else {
  339.         winW = winH = (multibuf ? 300 : 600);
  340.         winX = (DisplayWidth(dpy, DefaultScreen(dpy)) - winW) >> 1;
  341.         winY = (DisplayHeight(dpy, DefaultScreen(dpy)) - winH) >> 1;
  342.         if (geom) 
  343.             XParseGeometry(geom, &winX, &winY,
  344.                        (unsigned int *)&winW,
  345.                        (unsigned int *)&winH);
  346.  
  347.         xswa.event_mask = ExposureMask | StructureNotifyMask;
  348.         xswa.background_pixel = bg;
  349.         xswa.border_pixel = fg;
  350.         draw_window = XCreateWindow(dpy, DefaultRootWindow(dpy), 
  351.             winX, winY, winW, winH, 0, 
  352.             DefaultDepth(dpy, DefaultScreen(dpy)), 
  353.             InputOutput, DefaultVisual(dpy, DefaultScreen(dpy)),
  354.             CWEventMask | CWBackPixel | CWBorderPixel, &xswa);
  355.         XChangeProperty(dpy, draw_window, XA_WM_NAME, XA_STRING, 8, 
  356.                 PropModeReplace, (unsigned char *)"Ico", 3);
  357.         XMapWindow(dpy, draw_window);
  358.         while (1) {
  359.             XNextEvent(dpy, &xev);
  360.             if (xev.type == Expose)
  361.             break;
  362.         }
  363.         if (XGetWindowAttributes(dpy,draw_window,&xwa)==0) {
  364.             icoFatal("cant get window attributes (size)");
  365.         }
  366.         winW = xwa.width;
  367.         winH = xwa.height;
  368.         }
  369.  
  370.     if (ico_geom) 
  371.       XParseGeometry (ico_geom, &icoX, &icoY,
  372.               (unsigned int *)&icoW,
  373.               (unsigned int *)&icoH);
  374.     if (icoW <= 0) icoW = DEFAULT_ICO_WIDTH;
  375.     if (icoH <= 0) icoH = DEFAULT_ICO_HEIGHT;
  376.     if (icoW < MIN_ICO_WIDTH) icoW = MIN_ICO_WIDTH;
  377.     if (icoH < MIN_ICO_HEIGHT) icoH = MIN_ICO_HEIGHT;
  378.  
  379.     if (delta_geom) {
  380.         unsigned int junk;
  381.  
  382.         XParseGeometry (delta_geom, &icoDeltaX, &icoDeltaY, &junk, &junk);
  383.         if (icoDeltaX == 0 && icoDeltaY == 0) {
  384.         icoDeltaX = DEFAULT_DELTAX;
  385.         icoDeltaY = DEFAULT_DELTAY;
  386.         }
  387.     }
  388.  
  389.     win = None;
  390.  
  391. #ifdef MULTIBUFFER
  392.     if (multibuf) {
  393.         if (XmbufCreateBuffers (dpy, draw_window, 2, update_action,
  394.                     MultibufferUpdateHintFrequent,
  395.                     multibuffers) == 2) {
  396.         XCopyArea (dpy, draw_window, multibuffers[1],
  397.                DefaultGC(dpy, DefaultScreen(dpy)),
  398.                0, 0, winW, winH, 0, 0);
  399.         win = multibuffers[1];
  400.         } else 
  401.           icoFatal ("unable to obtain 2 buffers");
  402.         dblbuf = 1;
  403.     }
  404. #endif /* MULTIBUFFER */
  405.     if (win == None) win = draw_window;
  406.  
  407.     /* whether or not we are emulating */
  408.     softdbl = (dblbuf && !multibuf);
  409.  
  410.  
  411.     /* Set up a graphics context: */
  412.  
  413.     vmask = (GCBackground | GCForeground | GCLineWidth);
  414.     xgcv.background = bg;
  415.     xgcv.foreground = fg;
  416.     xgcv.line_width = linewidth;
  417.     if (dash) {
  418.         xgcv.line_style = LineDoubleDash;
  419.         xgcv.dashes = dash;
  420.         vmask |= (GCLineStyle | GCDashList);
  421.     }
  422.     gc = XCreateGC (dpy, draw_window, vmask, &xgcv);
  423.  
  424.     if (dofaces && numcolors>1) {
  425.         int i,t,bits;
  426.         bits = 0;
  427.         for (t=numcolors; t; t=t>>1) bits++;
  428.         initDBufs(fg,bg,bits);
  429.         /* don't set the background color */
  430.         for (i=0; i<numcolors; i++) {
  431.             setBufColname(i+1,colornames[i]);
  432.         }
  433.         initcolors = 1;
  434.     }
  435.     else if (dblbuf || dofaces) {
  436.         initDBufs(fg,bg,1);
  437.         initcolors = 1;
  438.     }
  439.     if (initcolors) {
  440.         setDisplayBuf(dblbuf?1:0);    /* insert new colors */
  441.     }
  442.     if (!numcolors) numcolors=1;
  443.  
  444.     if (dsync)
  445.         XSync(dpy, 0);
  446.  
  447.     /* Get the initial position, size, and speed of the bounding-box: */
  448.  
  449.     srand((int) time(0) % 231);
  450.     icoX = ((winW - icoW) * (rand() & 0xFF)) >> 8;
  451.     icoY = ((winH - icoH) * (rand() & 0xFF)) >> 8;
  452.  
  453.  
  454.     /* Bounce the box in the window: */
  455.  
  456.     icodeltax2 = icoDeltaX * 2;
  457.     icodeltay2 = icoDeltaY * 2;
  458.     for (;;)
  459.         {
  460.         int prevX;
  461.         int prevY;
  462.  
  463.         if (blocking || XPending(dpy)) {
  464.             XNextEvent(dpy, &xev);
  465.  
  466.             switch (xev.type) {
  467.               case ConfigureNotify:
  468.             if (xev.xconfigure.width != winW ||
  469.                 xev.xconfigure.height != winH)
  470.               icoX = icoY = 1;
  471.             winW = xev.xconfigure.width;
  472.             winH = xev.xconfigure.height;
  473.             break;
  474.               case MapNotify:
  475.             blocking = False;
  476.             break;
  477.               case UnmapNotify:
  478.             blocking = True;
  479.             continue;
  480.             }
  481.         }
  482.  
  483.         prevX = icoX;
  484.         prevY = icoY;
  485.  
  486.         icoX += icoDeltaX;
  487.         if (icoX < 0 || icoX + icoW > winW)
  488.             {
  489.             icoX -= icodeltax2;
  490.             icoDeltaX = - icoDeltaX;
  491.             icodeltax2 = icoDeltaX * 2;
  492.             }
  493.         icoY += icoDeltaY;
  494.         if (icoY < 0 || icoY + icoH > winH)
  495.             {
  496.             icoY -= icodeltay2;
  497.             icoDeltaY = - icoDeltaY;
  498.             icodeltay2 = icoDeltaY * 2;
  499.             }
  500.  
  501.         drawPoly(poly, gc, icoX, icoY, icoW, icoH, prevX, prevY);
  502.         }
  503.     }
  504.  
  505. giveObjHelp()
  506. {
  507. int i;
  508. Polyinfo *poly;
  509.     printf("%-16s%-12s  #Vert.  #Edges  #Faces  %-16s\n",
  510.         "Name", "ShortName", "Dual");
  511.     for (i=0; i<polysize; i++) {
  512.         poly = polys+i;
  513.         printf("%-16s%-12s%6d%8d%8d    %-16s\n",
  514.             poly->longname, poly->shortname,
  515.             poly->numverts, poly->numedges, poly->numfaces,
  516.             poly->dual);
  517.     }
  518. }
  519.  
  520. Polyinfo *
  521. findpoly(name)
  522. char *name;
  523. {
  524. int i;
  525. Polyinfo *poly;
  526.     for (i=0; i<polysize; i++) {
  527.         poly = polys+i;
  528.         if (strcmp(name,poly->longname)==0 ||
  529.             strcmp(name,poly->shortname)==0) return poly;
  530.     }
  531.     icoFatal("can't find object %s", name);
  532. }
  533.  
  534. icoClearArea(x,y,w,h)
  535. int x,y,w,h;
  536. {
  537.     if (multibuf) return;
  538.  
  539.     if (dblbuf || dofaces) {
  540.         XSetForeground(dpy, gc, dbpair.drawbuf->pixels[0]);
  541.             /* use background as foreground color for fill */
  542.         XFillRectangle(dpy,win,gc,x,y,w,h);
  543.     }
  544.     else {
  545.         XClearArea(dpy,win,x,y,w,h,0);
  546.     }
  547. }
  548.  
  549. /******************************************************************************
  550.  * Description
  551.  *    Undraw previous polyhedron (by erasing its bounding box).
  552.  *    Rotate and draw the new polyhedron.
  553.  *
  554.  * Input
  555.  *    poly        the polyhedron to draw
  556.  *    gc        X11 graphics context to be used for drawing
  557.  *    icoX, icoY    position of upper left of bounding-box
  558.  *    icoW, icoH    size of bounding-box
  559.  *    prevX, prevY    position of previous bounding-box
  560.  *****************************************************************************/
  561. char drawn[MAXNV][MAXNV];
  562.  
  563. drawPoly(poly, gc, icoX, icoY, icoW, icoH, prevX, prevY)
  564. Polyinfo *poly;
  565. GC gc;
  566. int icoX, icoY, icoW, icoH;
  567. int prevX, prevY;
  568.     {
  569.     static int initialized = 0;
  570.  
  571.     Point3D *v = poly->v;
  572.     int *f = poly->f;
  573.     int NV = poly->numverts;
  574.     int NF = poly->numfaces;
  575.  
  576.     static Transform3D xform;
  577.     static Point3D xv[2][MAXNV];
  578.     static int buffer;
  579.     register int p0;
  580.     register int p1;
  581.     register XPoint *pv2;
  582.     XSegment *pe;
  583.     register Point3D *pxv;
  584.     static double wo2, ho2;
  585.     XPoint v2[MAXNV];
  586.     XSegment edges[MAXEDGES];
  587.     register int i;
  588.     int j,k;
  589.     register int *pf;
  590.     int facecolor;
  591.  
  592.     int pcount;
  593.     double pxvz;
  594.     XPoint ppts[MAXEDGESPERPOLY];
  595.  
  596.     /* Set up points, transforms, etc.:  */
  597.  
  598.     if (!initialized)    
  599.         {
  600.         Transform3D r1;
  601.         Transform3D r2;
  602.  
  603.         FormatRotateMat('x', 5 * 3.1416 / 180.0, r1);
  604.         FormatRotateMat('y', 5 * 3.1416 / 180.0, r2);
  605.         ConcatMat(r1, r2, xform);
  606.  
  607.         bcopy((char *) v, (char *) xv[0], NV * sizeof(Point3D));
  608.         buffer = 0;
  609.  
  610.         wo2 = icoW / 2.0;
  611.         ho2 = icoH / 2.0;
  612.  
  613.         initialized = 1;
  614.         }
  615.  
  616.  
  617.     /* Switch double-buffer and rotate vertices: */
  618.  
  619.     buffer = !buffer;
  620.     PartialNonHomTransform(NV, xform, xv[!buffer], xv[buffer]);
  621.  
  622.  
  623.     /* Convert 3D coordinates to 2D window coordinates: */
  624.  
  625.     pxv = xv[buffer];
  626.     pv2 = v2;
  627.     for (i = NV - 1; i >= 0; --i)
  628.         {
  629.         pv2->x = (int) ((pxv->x + 1.0) * wo2) + icoX;
  630.         pv2->y = (int) ((pxv->y + 1.0) * ho2) + icoY;
  631.         ++pxv;
  632.         ++pv2;
  633.         }
  634.  
  635.  
  636.     /* Accumulate edges to be drawn, eliminating duplicates for speed: */
  637.  
  638.     pxv = xv[buffer];
  639.     pv2 = v2;
  640.     pf = f;
  641.     pe = edges;
  642.     bzero(drawn, sizeof(drawn));
  643.  
  644.     if (dblbuf)
  645.         setDrawBuf(dbpair.dbufnum);
  646.             /* switch drawing buffers if double buffered */
  647.     /* for faces, need to clear before FillPoly */
  648.     if (dofaces && !multibuf) {    /* multibuf uses update background */
  649.         if (softdbl)
  650.             icoClearArea(
  651.                 dbpair.drawbuf->prevX, dbpair.drawbuf->prevY,
  652.                 icoW + 1, icoH + 1);
  653.         icoClearArea(prevX, prevY, icoW + 1, icoH + 1);
  654.     }
  655.  
  656.     if (dsync)
  657.         XSync(dpy, 0);
  658.  
  659.     for (i = NF - 1; i >= 0; --i, pf += pcount)
  660.         {
  661.  
  662.         pcount = *pf++;    /* number of edges for this face */
  663.         pxvz = 0.0;
  664.         for (j=0; j<pcount; j++) {
  665.             p0 = pf[j];
  666.             pxvz += pxv[p0].z;
  667.         }
  668.  
  669.         /* If facet faces away from viewer, don't consider it: */
  670.         if (pxvz<0.0)
  671.             continue;
  672.  
  673.         if (dofaces) {
  674.             if (numcolors)
  675.                 facecolor = i%numcolors + 1;
  676.             else    facecolor = 1;
  677.             XSetForeground(dpy, gc,
  678.                 dbpair.drawbuf->pixels[facecolor]);
  679.             for (j=0; j<pcount; j++) {
  680.                 p0 = pf[j];
  681.                 ppts[j].x = pv2[p0].x;
  682.                 ppts[j].y = pv2[p0].y;
  683.             }
  684.             XFillPolygon(dpy, win, gc, ppts, pcount,
  685.                 Convex, CoordModeOrigin);
  686.         }
  687.  
  688.         if (doedges) {
  689.             for (j=0; j<pcount; j++) {
  690.                 if (j<pcount-1) k=j+1;
  691.                 else k=0;
  692.                 p0 = pf[j];
  693.                 p1 = pf[k];
  694.                 if (!drawn[p0][p1]) {
  695.                     drawn[p0][p1] = 1;
  696.                     drawn[p1][p0] = 1;
  697.                     pe->x1 = pv2[p0].x;
  698.                     pe->y1 = pv2[p0].y;
  699.                     pe->x2 = pv2[p1].x;
  700.                     pe->y2 = pv2[p1].y;
  701.                     ++pe;
  702.                 }
  703.             }
  704.         }
  705.         }
  706.  
  707.     /* Erase previous, draw current icosahedrons; sync for smoothness. */
  708.  
  709.     if (doedges) {
  710.         if (dofaces) {
  711.             XSetForeground(dpy, gc, dbpair.drawbuf->pixels[0]);
  712.                 /* use background as foreground color */
  713.         }
  714.         else {
  715.             if (softdbl)
  716.                 icoClearArea(dbpair.drawbuf->prevX,
  717.                     dbpair.drawbuf->prevY,
  718.                     icoW + 1, icoH + 1);
  719.             if (!multibuf)
  720.               icoClearArea(prevX, prevY, icoW + 1, icoH + 1);
  721.             if (dblbuf || dofaces) {
  722.                 XSetForeground(dpy, gc, dbpair.drawbuf->pixels[
  723.                     dbpair.pixelsperbuf-1]);
  724.             }
  725.         }
  726.         XDrawSegments(dpy, win, gc, edges, pe - edges);
  727.     }
  728.  
  729.     if (dsync)
  730.         XSync(dpy, 0);
  731.  
  732.     if (dblbuf) {
  733.         dbpair.drawbuf->prevX = icoX;
  734.         dbpair.drawbuf->prevY = icoY;
  735.         setDisplayBuf(dbpair.dbufnum);
  736.     }
  737.     if (dblbuf)
  738.         dbpair.dbufnum = 1 - dbpair.dbufnum;
  739.     if (!multibuf && sleepcount) sleep(sleepcount);
  740.     }
  741.  
  742. char *xalloc(nbytes)
  743. int nbytes;
  744. {
  745. #ifndef MSDOS
  746. char *p, *malloc();
  747. #else
  748. char *p;
  749. #endif
  750.  
  751.     p = malloc((unsigned int)nbytes);
  752.     if (p) return p;
  753.     fprintf(stderr,"ico: no more memory\n");
  754.     exit(1);
  755. }
  756.  
  757. initDBufs(fg,bg,planesperbuf)
  758. int fg,bg;
  759. int planesperbuf;
  760. {
  761. int i,j,jj,j0,j1,k,m,t;
  762. DBufInfo *b, *otherb;
  763.  
  764.     nplanesets = (softdbl ? 2 : 1);
  765.  
  766.     dbpair.planesperbuf = planesperbuf;
  767.     dbpair.pixelsperbuf = 1<<planesperbuf;
  768.     dbpair.totalplanes = nplanesets * planesperbuf;
  769.     dbpair.totalpixels = 1<<dbpair.totalplanes;
  770.     dbpair.plane_masks = (unsigned long *)
  771.         xalloc(dbpair.totalplanes * sizeof(unsigned long));
  772.     dbpair.dbufnum = 0;
  773.     for (i=0; i < nplanesets; i++) {
  774.         b = dbpair.bufs+i;
  775.         b->plane_masks = dbpair.plane_masks + (i*planesperbuf);
  776.         b->colors = (XColor *)
  777.             xalloc(dbpair.totalpixels * sizeof(XColor));
  778.         b->pixels = (unsigned long *)
  779.             xalloc(dbpair.pixelsperbuf * sizeof(unsigned long));
  780.     }
  781.  
  782.     if (dbpair.totalplanes == 1) {
  783.         dbpair.pixels[0] = bg;
  784.         dbpair.plane_masks[0] = fg ^ bg;
  785.     } else {
  786.         t = XAllocColorCells(dpy,cmap,0,
  787.             dbpair.plane_masks,dbpair.totalplanes, dbpair.pixels,1);
  788.                 /* allocate color planes */
  789.         if (t==0) {
  790.             icoFatal("can't allocate enough color planes");
  791.         }
  792.     }
  793.  
  794.     fgcolor.pixel = fg;
  795.     bgcolor.pixel = bg;
  796.     XQueryColor(dpy,cmap,&fgcolor);
  797.     XQueryColor(dpy,cmap,&bgcolor);
  798.  
  799.     setBufColor(0,&bgcolor);
  800.     setBufColor(1,&fgcolor);
  801.     for (i=0; i<nplanesets; i++) {
  802.         b = dbpair.bufs+i;
  803.         if (dblbuf)
  804.             otherb = dbpair.bufs+(1-i);
  805.         for (j0=0; j0<(softdbl?dbpair.pixelsperbuf:1); j0++) {
  806.             for (j1=0; j1<dbpair.pixelsperbuf; j1++) {
  807.             j = (j0<<dbpair.planesperbuf)|j1;
  808.             if (i==0) jj=j;
  809.             else jj= (j1<<dbpair.planesperbuf)|j0;
  810.             b->colors[jj].pixel = dbpair.pixels[0];
  811.             for (k=0, m=j; m; k++, m=m>>1) {
  812.                 if (m&1)
  813.                    b->colors[jj].pixel ^= dbpair.plane_masks[k];
  814.             }
  815.             b->colors[jj].flags = DoRed | DoGreen | DoBlue;
  816.             }
  817.         }
  818.         b->prevX = b->prevY = 0;
  819.         b->enplanemask = 0;
  820.         for (j=0; j<planesperbuf; j++) {
  821.             b->enplanemask |= b->plane_masks[j];
  822.         }
  823.         for (j=0; j<dbpair.pixelsperbuf; j++) {
  824.             b->pixels[j] = dbpair.pixels[0];
  825.             for (k=0, m=j; m; k++, m=m>>1) {
  826.                 if (m&1)
  827.                    b->pixels[j] ^= b->plane_masks[k];
  828.             }
  829.         }
  830.     }
  831.  
  832.     if (!multibuf) {
  833.         setDrawBuf(0);
  834.         XSetBackground(dpy, gc, dbpair.bufs[0].pixels[0]);
  835.         XSetWindowBackground(dpy, draw_window, dbpair.bufs[0].pixels[0]);
  836.         XSetPlaneMask(dpy, gc, AllPlanes);
  837.         icoClearArea(0, 0, winW, winH); /* clear entire window */
  838.     }
  839.  
  840. /*    if (softdbl) setDisplayBuf(1); */
  841. }
  842.  
  843. setBufColname(n,colname)
  844. int n;
  845. char *colname;
  846. {
  847. int t;
  848. XColor dcolor, color;
  849.  
  850.     t = XLookupColor(dpy,cmap,colname,&dcolor,&color);
  851.     if (t==0) {    /* no such color */
  852.         icoFatal("no such color %s",colname);
  853.     }
  854.     setBufColor(n,&color);
  855. }
  856.  
  857. setBufColor(n,color)
  858. int n;        /* color index */
  859. XColor *color;    /* color to set */
  860. {
  861. int i,j,cx;
  862. DBufInfo *b;
  863. unsigned long pix;
  864.  
  865.     for (i=0; i<nplanesets; i++) {
  866.         b = dbpair.bufs+i;
  867.         for (j=0; j<(softdbl?dbpair.pixelsperbuf:1); j++) {
  868.             cx = n + j*dbpair.pixelsperbuf;
  869.             pix = b->colors[cx].pixel;
  870.             b->colors[cx] = *color;
  871.             b->colors[cx].pixel = pix;
  872.             b->colors[cx].flags = DoRed | DoGreen | DoBlue;
  873.         }
  874.     }
  875. }
  876.  
  877. setDrawBuf (n)
  878.     int n;
  879. {
  880.     XGCValues xgcv;
  881.     unsigned long mask;
  882.  
  883. #ifdef MULTIBUFFER
  884.     if (multibuf) {
  885.     win = multibuffers[n];
  886.     n = 0;
  887.     }
  888. #endif /* MULTIBUFFER */
  889.  
  890.     dbpair.drawbuf = dbpair.bufs+n;
  891.     xgcv.foreground = dbpair.drawbuf->pixels[dbpair.pixelsperbuf-1];
  892.     xgcv.background = dbpair.drawbuf->pixels[0];
  893.     mask = GCForeground | GCBackground;
  894.     if (softdbl) {
  895.     xgcv.plane_mask = dbpair.drawbuf->enplanemask;
  896.     mask |= GCPlaneMask;
  897.     }
  898.     XChangeGC(dpy, gc, mask, &xgcv);
  899. }
  900.  
  901. setDisplayBuf(n)
  902. int n;
  903. {
  904. #if MULTIBUFFER
  905.     if (multibuf) {
  906.     static int firsttime = 1;
  907.  
  908.     XmbufDisplayBuffers (dpy, 1, &multibuffers[n], msleepcount, 0);
  909.     if (firsttime) {
  910.         firsttime = 0;
  911.         n = 0;
  912.         goto storecolors;
  913.     }
  914.     } else
  915. #endif
  916.     {
  917.       storecolors:
  918.     dbpair.dpybuf= dbpair.bufs+n;
  919.     if (dbpair.totalpixels > 2)
  920.         XStoreColors(dpy,cmap,dbpair.dpybuf->colors,dbpair.totalpixels);
  921.     }
  922. }
  923. #ifndef MSDOS
  924. icoFatal(fmt,a0)
  925. char *fmt;
  926. #else
  927. void icoFatal(char *fmt,...)
  928. #endif
  929. {
  930. #ifndef MSDOS
  931.     fprintf(stderr,"ico: ");
  932.     fprintf(stderr,fmt,a0);
  933.     fprintf(stderr,"\n");
  934.     exit(1);
  935. #else
  936.    va_list argptr;
  937.     fprintf(stderr,"ico: ");
  938.    va_start(argptr,fmt);
  939.    vfprintf(stderr,fmt,argptr);
  940.    va_end(argptr);
  941.     fprintf(stderr,"\n");
  942.     exit(1);
  943. #endif
  944. }
  945.  
  946. /******************************************************************************
  947.  * Description
  948.  *    Concatenate two 4-by-4 transformation matrices.
  949.  *
  950.  * Input
  951.  *    l        multiplicand (left operand)
  952.  *    r        multiplier (right operand)
  953.  *
  954.  * Output
  955.  *    *m        Result matrix
  956.  *****************************************************************************/
  957.  
  958. ConcatMat(l, r, m)
  959. register Transform3D l;
  960. register Transform3D r;
  961. register Transform3D m;
  962.     {
  963.     register int i;
  964.     register int j;
  965.  
  966.     for (i = 0; i < 4; ++i)
  967.         for (j = 0; j < 4; ++j)
  968.             m[i][j] = l[i][0] * r[0][j]
  969.                 + l[i][1] * r[1][j]
  970.                 + l[i][2] * r[2][j]
  971.                 + l[i][3] * r[3][j];
  972.     }
  973.  
  974.  
  975.  
  976. /******************************************************************************
  977.  * Description
  978.  *    Format a matrix that will perform a rotation transformation
  979.  *    about the specified axis.  The rotation angle is measured
  980.  *    counterclockwise about the specified axis when looking
  981.  *    at the origin from the positive axis.
  982.  *
  983.  * Input
  984.  *    axis        Axis ('x', 'y', 'z') about which to perform rotation
  985.  *    angle        Angle (in radians) of rotation
  986.  *    A        Pointer to rotation matrix
  987.  *
  988.  * Output
  989.  *    *m        Formatted rotation matrix
  990.  *****************************************************************************/
  991.  
  992. FormatRotateMat(axis, angle, m)
  993. char axis;
  994. double angle;
  995. register Transform3D m;
  996.     {
  997.     double s, c;
  998.     double sin(), cos();
  999.  
  1000.     IdentMat(m);
  1001.  
  1002.     s = sin(angle);
  1003.     c = cos(angle);
  1004.  
  1005.     switch(axis)
  1006.         {
  1007.         case 'x':
  1008.             m[1][1] = m[2][2] = c;
  1009.             m[1][2] = s;
  1010.             m[2][1] = -s;
  1011.             break;
  1012.         case 'y':
  1013.             m[0][0] = m[2][2] = c;
  1014.             m[2][0] = s;
  1015.             m[0][2] = -s;
  1016.             break;
  1017.         case 'z':
  1018.             m[0][0] = m[1][1] = c;
  1019.             m[0][1] = s;
  1020.             m[1][0] = -s;
  1021.             break;
  1022.         }
  1023.     }
  1024.  
  1025.  
  1026.  
  1027. /******************************************************************************
  1028.  * Description
  1029.  *    Format a 4x4 identity matrix.
  1030.  *
  1031.  * Output
  1032.  *    *m        Formatted identity matrix
  1033.  *****************************************************************************/
  1034.  
  1035. IdentMat(m)
  1036. register Transform3D m;
  1037.     {
  1038.     register int i;
  1039.     register int j;
  1040.  
  1041.     for (i = 3; i >= 0; --i)
  1042.         {
  1043.         for (j = 3; j >= 0; --j)
  1044.             m[i][j] = 0.0;
  1045.         m[i][i] = 1.0;
  1046.         }
  1047.     }
  1048.  
  1049.  
  1050.  
  1051. /******************************************************************************
  1052.  * Description
  1053.  *    Perform a partial transform on non-homogeneous points.
  1054.  *    Given an array of non-homogeneous (3-coordinate) input points,
  1055.  *    this routine multiplies them by the 3-by-3 upper left submatrix
  1056.  *    of a standard 4-by-4 transform matrix.  The resulting non-homogeneous
  1057.  *    points are returned.
  1058.  *
  1059.  * Input
  1060.  *    n        number of points to transform
  1061.  *    m        4-by-4 transform matrix
  1062.  *    in        array of non-homogeneous input points
  1063.  *
  1064.  * Output
  1065.  *    *out        array of transformed non-homogeneous output points
  1066.  *****************************************************************************/
  1067.  
  1068. PartialNonHomTransform(n, m, in, out)
  1069. int n;
  1070. register Transform3D m;
  1071. register Point3D *in;
  1072. register Point3D *out;
  1073.     {
  1074.     for (; n > 0; --n, ++in, ++out)
  1075.         {
  1076.         out->x = in->x * m[0][0] + in->y * m[1][0] + in->z * m[2][0];
  1077.         out->y = in->x * m[0][1] + in->y * m[1][1] + in->z * m[2][1];
  1078.         out->z = in->x * m[0][2] + in->y * m[1][2] + in->z * m[2][2];
  1079.         }
  1080.     }
  1081.